/* Copyright 2012 Optimum Semiconductor Technologies, Inc.
 * All rights reserved.
 */

#ifndef _armxdsp_impl_h_
#define _armxdsp_impl_h_

#include "dspmap.h"

/*
 * Message queue slot header;
 * this data structure is used internally and should not be used by applications.
 */
struct armxdsp_mq_slot {
    /* size of the slot buffer in bytes */
    uint32_t size;
    /* total number of bytes used by messages in this slot; this field is
       incremented by writer and decremented by reader; both reader
       and writer must aquire queue lock before moifying this field;
       this number is always in [0,'size'] range */
    uint32_t used_size;
    /* address of the slot buffer relative to the address of the parent
       message queue */
    uint32_t address;
    /* message writing position relative to the beginning of the slot buffer;
       this number is always in [0,'size') range */
    uint32_t wpos;
    /* message reading position relative to the beginning of the slot buffer
       this number is always in [0,'size') range */
    uint32_t rpos;
    /* padding */
    uint32_t padding[3];
};

/*
 * Message queue header;
 * this data structure is used internally and should not be used by applications;
 * the total number of bytes occupied by a message queue can be computed
 * as follows:
 *     ARMXDSP_MQ_SIZE(N)
 *     + ARMXDSP_SLOT_SIZE(size_1)
 *     + ...
 *     + ARMXDSP_SLOT_SIZE(size_N)
 * where N is the number of slots in the queue; size_[1,N] is the size of
 * each slot;
 */
struct armxdsp_mq {
    /* the number of slots in this queue */
    uint32_t slot_count;
    /* a bit in this number is set to 1 if the corresponding
       slot has a message available for reading, otherwise it is set to 0 */
    uint32_t msg_ready;
    /* the following array of 4 bytes is used to implement a two-process mutual
       exclusion lock */
    uint8_t lock[4];
    /* 留作将来使用 */
    uint32_t reserved;
    /* all the slot headers are allocated sequentially starting from
       this point; the slot buffers are allocated sequentially after
       the headers */
    armxdsp_mq_slot_t slots[1];
} ;


#if defined(__SANDBLASTER__)
#define ARMXDSP_ASSERT(c)
#else
#define ARMXDSP_ASSERT(c) SYS_ASSERT(c)
#endif

#ifndef ARMXDSP_CHECK_ARGS
#define ARMXDSP_CHECK_ARGS 0
#endif

/*
 * 的最大数量DSP内核支持的API。
 */
#define ARMXDSP_DSP_COUNT 3

#define MSGQ_BUF_SIZE     2400

#define GET_SLOT_DATA(mq,slot,pos) ((uint32_t*)((char*)(mq) + (slot)->address + (pos)))

#define GET_SLOT_FREE_SPACE(slot) ((slot)->size-(slot)->used_size)

#define MESSAGE_SIZE(x) (4+(((x)+3)&~3))

static armxdsp_mq_t* in_queues[ARMXDSP_DSP_COUNT];
static armxdsp_mq_t* out_queues[ARMXDSP_DSP_COUNT];

#define ARMXDSP_MQ_POINTERS_TAG 0x4D534751/*'MSGQ'*/
#define ARMXDSP_MQ_POINTERS_MAX_COUNT 4

typedef struct armxdsp_mq_pointers {
    uint32_t tag;
    uint32_t size;
    armxdsp_mq_t* arm_to_dsp[ARMXDSP_MQ_POINTERS_MAX_COUNT];
    armxdsp_mq_t* dsp_to_arm[ARMXDSP_MQ_POINTERS_MAX_COUNT];
} armxdsp_mq_pointers_t;

#ifdef KERNEL_UCLINUX
  extern void linux_kerenl_delay(uint32_t ms);
  #define POLL_DELAY()  linux_kerenl_delay(1)
  #define BLOCK_DELAY() linux_kerenl_delay(1)
#else
/* 以下宏用于内存轮询循环 */
  extern void spin_idle(volatile unsigned count);
  #define POLL_DELAY()  spin_idle(100)
  #define BLOCK_DELAY() spin_idle(100)
#endif

#endif
/* vim:se ts=4 sw=4: */
